/***********************************************************************
 * 
 *  This file is a part of Minesweeper - a computer game
 *  Copyright (C) 2020, 2021 Andrew Tokarskiy <tokarskiy.a@keemail.me>
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>
 * 
*************************************************************************/

#include "mines.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#define COMMAND_BUFFER_SIZE 32
#define DEFAULT_WIDTH 10
#define DEFAULT_HEIGHT 10
#define DEFAULT_MINES 20

void outputGameConsole(Game* const game) {
    int** statuses = game->statuses; 
    {
        printf("  "); 
	    for (int j = 0; j < game->width; j++)
        {
            const int jLastDigit = (j + 1) % 10; 
	        printf("%d ", jLastDigit); 
        }

	    printf("\n"); 
    }


    for (int i = 0; i < game->height; i++) {
        const int iLastDigit = (i + 1) % 10; 
        printf("%d ", iLastDigit);
        	
        for (int j = 0; j < game->width; j++) {
            const int status = statuses[i][j];
            switch (status) {
                case STATUS_NULL:
                    printf("_ ");
                    break;
                case STATUS_FLAG:
                    printf("F ");
                    break; 
                case STATUS_MINE:
                    printf("M ");
                    break; 
                case 0:
                    printf("  "); 
                    break; 
                default:
                    printf("%d ", status); 
                    break; 
            }
        }

        printf("\n"); 
    }
}

typedef struct {
    int i; 
    int j; 
    ActionType command; 
    int parseStatus; 
} 
Turn; 

Turn parseTurn(Game* const game, char* command, const int n) {
    char* token = strtok(command, " "); 
    if (token == NULL) {
        Turn turn; 
        turn.parseStatus = 0; 
        return turn;  
    }

    char* commandStr = token; 
    token = strtok(NULL, " ");
    if (token == NULL) {
        Turn turn; 
        turn.parseStatus = 0; 
        return turn;  
    }

    char* xStr = token; 
    token = strtok(NULL, " "); 
    if (token == NULL) {
        Turn turn; 
        turn.parseStatus = 0; 
        return turn;  
    }

    char* yStr = token; 
    const int x = atoi(xStr); 
    const int y = atoi(yStr); 
    if (x <= 0 || x > game->width || y <= 0 || y > game->height) {
        Turn turn; 
        turn.parseStatus = 0; 
        return turn;  
    }

    ActionType type; 
    if (strcmp(commandStr, "flag") == 0) {
        type = MarkMine;
    }
    else if (strcmp(commandStr, "click") == 0) {
        type = Click; 
    }
    else {
        Turn turn; 
        turn.parseStatus = 0; 
        return turn;  
    }

    Turn turn; 
    turn.i = y - 1;
    turn.j = x - 1; 
    turn.command = type; 
    turn.parseStatus = 1;

    return turn; 
}

typedef struct {
    int width; 
    int height; 
    int mines; 
} InitData; 

InitData parseArgs(char* args[], int n) {
    InitData data; 
    data.width = DEFAULT_WIDTH;
    data.height = DEFAULT_HEIGHT; 
    data.mines = DEFAULT_MINES; 

    int i = 1;
    while (i < n - 1) {
        if (strcmp("--width", args[i]) == 0) {
            const int w = atoi(args[i + 1]); 
            if (w > 0) {
                data.width = w; 
            }

            i++; 
        }

        if (strcmp("--height", args[i]) == 0) {
            const int h = atoi(args[i + 1]); 
            if (h > 0) {
                data.height = h; 
            }

            i++; 
        }

        if (strcmp("--mines", args[i]) == 0) {
            const int m = atoi(args[i + 1]); 
            if (m > 0) {
                data.mines = m; 
            }

            i++; 
        }

        i++; 
    }

    return data; 
}

void printGreetings() {
    printf("--- MINESWEEPER ---\n"); 
    printf("\n");
    printf("How to play: \n"); 
    printf("  click <x> <y>: click on cell with coords x and y.\n");
    printf("  flag <x> <y>: flag mine on cell with coords x and y.\n");
    printf("Numeration of coords starts from 1\n"); 
    printf("\n");
    printf("Good luck!\n"); 
}

int main(int argc, char* argv[]) {
    char command[COMMAND_BUFFER_SIZE];
    printGreetings(); 

    srand(time(NULL)); 

    const InitData parse = parseArgs(argv, argc); 

    Game* game = initGame(parse.height, parse.width, parse.mines); 
    outputGameConsole(game); 

    while (1) {
        printf("> "); 

        fgets(command, COMMAND_BUFFER_SIZE, stdin);
        const Turn turnData = parseTurn(game, command, COMMAND_BUFFER_SIZE); 
        if (turnData.parseStatus == 0) {
            printf("Error!\n"); 
            continue; 
        }

        ActionResult actionStatus = action(game, turnData.i, turnData.j, turnData.command); 
        outputGameConsole(game); 
        if (actionStatus == Lose) {
            printf("Lose...\n"); 
            break; 
        }

        if (actionStatus == Win) {
            printf("WIN!!!\n"); 
            break; 
        }
    }

    freeGame(game); 
}
